/**
 * 使用 ES 5 的语法来模拟一个生成器
 * @param promiseFn
 * @returns {function(): {next: function(*): ({done: boolean, value: *}), throw: function(*): void}}
 */
module.exports.simulateGenerator = function (promiseFn) {
    /**
     * 使用闭包保存 promise 函数、迭代器的状态、迭代器的值
     */
    const promiseFunction = promiseFn

    let status

    let value

    /**
     * 第一次调用最外层方法时，返回一个 方法，此方法会被当作一个迭代器
     * */
    return function () {

        /**
         * 精髓：生成器与辅助函数（myRun.js、async await）之间的交互仅通过迭代器的接口进行数据的交互
         * */
        return {
            next: function (input) {
                if (!status) {
                    /**
                     * 第一次调用 next() 启动生成器，使用 value 保存promise
                     * 并返回promise
                     * */
                    status = 1
                    value = promiseFunction.call(this)
                    return {
                        done: false,
                        value
                    }
                } else {
                    switch (status) {
                        case 1: {
                            /**
                             * 第二次调用 next() 就是代表 promise 已经 resolve() ，并通过 next("promise resolve 后的结果") 传入
                             * */
                            status = 2
                            value = input
                            console.log("执行完成", value.data)
                            return {
                                done: true,
                                value
                            }
                        }
                        case 2:{
                            return {
                                done: true,
                                value
                            }
                        }
                        case 3: {
                            console.err("执行异常", value.data)
                            return {
                                done: true,
                                value
                            }
                        }

                    }
                }
            },
            "throw": function (err) {
                switch (status) {
                    case 1: {
                        status = 3
                        value = err
                        break
                    }
                    default: {
                        throw err
                    }
                }
            }
        }

    }


}
